// Copyright (c) ZeroC, Inc.

using Google.Protobuf;
using Google.Protobuf.Compiler;
using Google.Protobuf.Reflection;
using IceRpc.CaseConverter.Internal;
using IceRpc.ProtocGen;
using System.Text;

// The protoc compiler executes this program and writes the Protobuf serialized CodeGeneratorRequest to standard input.

// Read the input and deserialize it using the Protobuf CodeGeneratorRequest object.
using Stream stdin = Console.OpenStandardInput();
var request = new CodeGeneratorRequest();
request.MergeFrom(stdin);

// Extract Protobuf encoded data from the request's proto files.
var sources = new List<ByteString>();
foreach (FileDescriptorProto? proto in request.ProtoFile)
{
    sources.Add(proto.ToByteString());
}
// Build the FileDescriptor objects from the collected encoded data.
IReadOnlyList<FileDescriptor> descriptors = FileDescriptor.BuildFromByteStrings(sources);

var response = new CodeGeneratorResponse();
foreach (FileDescriptor descriptor in descriptors)
{
    if (!request.FileToGenerate.Contains(descriptor.Name))
    {
        // This descriptor represents a reference file for which we are not generating code.
        continue;
    }

    var builder = new StringBuilder();
    string preamble = $@"
// <auto-generated/>
// protoc-gen-icerpc-csharp version: {typeof(ClientGenerator).Assembly.GetName().Version!.ToString(3)}
// Generated from file: {descriptor.Name}

#nullable enable

#pragma warning disable CS1591 // Missing XML Comment
#pragma warning disable CS1573 // Parameter has no matching param tag in the XML comment
#pragma warning disable CS0612 // Type or member is obsolete
#pragma warning disable CS0618 // Type or member is obsolete
#pragma warning disable CS0619 // Type or member is obsolete

using IceRpc.Protobuf;

namespace {descriptor.GetCsharpNamespace()};".Trim();
    builder.AppendLine(preamble);

    foreach (ServiceDescriptor service in descriptor.Services)
    {
        builder.Append(ClientGenerator.GenerateInterface(service));
        builder.AppendLine();
        builder.Append(ClientGenerator.GenerateImplementation(service));
        builder.AppendLine();
        builder.Append(ServiceGenerator.GenerateInterface(service));
        builder.AppendLine();
    }

    response.File.Add(
        new CodeGeneratorResponse.Types.File
        {
            Name = $"{Path.GetFileNameWithoutExtension(descriptor.Name).ToPascalCase()}.IceRpc.cs",
            Content = builder.ToString().ReplaceLineEndings().RemoveSuperfluousEmptyLines()
        });
}

// Write the code generator response to the standard output.
// The protoc compiler will then write the corresponding generated files to disk.
using Stream stdout = Console.OpenStandardOutput();
response.WriteTo(stdout);
